module Account
    
    # mix this class into a user controller to get login functionality
    module AccountController
        
#        def self.included(base)
#            base.class_eval do
#                
#            end
#        end
        
        public
        # The action used to log a user in. If the user was redirected to the login page
        # by the login_required method, they should be sent back to the page they were
        # trying to access. If not, they will be sent to "/user/home".
        def signin
            
            return unless request.post?
            
            if user = User.authenticate(params[:login], params[:password])
                user.logged_in_at = Time.now
                user.save(false)
                
                if params[:remember_me] == "1"
                    user.remember_me
                    cookies[:auth_token] = { :value => user.remember_token , :expires => user.remember_token_expires_at }
                end
                self.current_user=user
                flash[:notice] = 'Login successful'
                redirect_back_or_default :action => 'logged_in'
            else
                flash.now[:warning] = 'Login unsuccessful'
            end
        end
        
        # Register as a new user.
        def signup
            
            success = false
            @user = User.new(params[:user])
            return unless request.post?
            
            begin
                success = @user.save
            rescue ActiveRecord::RecordInvalid
                render :action => 'signup' 
                success = false   
            end
            
            if success
                if AccountConfiguration.config(:use_email_notification)
                    url =  url_for(:action => 'activate', :activation_code => @user.activation_code)
                    
                    begin
                        email = UserNotify.create_signup(@user, url)
                        UserNotify.deliver(email)
                        
                        # redirect to a page letting the user know that they need to check their email
                        redirect_to :action => :check_email
                        return
                    rescue Exception => e
                        # unble to send activation email.  Activate the user anyway which means
                        # letting flow continue below
                        logger.error 'Unable to send confirmation E-Mail:'
                        logger.error e
                    end
                end
                
                if success
                    flash[:notice] = 'Signup successful!'
                    if @user.activate
                        
                        self.current_user = @user
                        
                        @user.logged_in_at = Time.now
                        @user.save
                        
                        redirect_to :action => 'welcome'
                    else
                        flash[:notice] = 'An error occured while attempting to activate your account.'
                    end
                end
            end
            
            
        end
        
        def signout
            current_user.forget_me if logged_in?
            cookies.delete :auth_token
            reset_session
            flash[:notice] = "You have been logged out."
            redirect_back_or_default(self.url_for(:action => 'signin'))
        end
        
        def activate
            if params[:activation_code]
                @user = User.find_by_activation_code(params[:activation_code]) 
                if @user and @user.activate
                    self.current_user = @user
                    redirect_back_or_default(:action => 'welcome')
                    flash[:notice] = 'Your account has been activated.'
                else
                    flash[:error] = 'Unable to activate the account.  Did you provide the correct information?'
                end
            else
                flash.clear
            end
        end  
        
        def check_email
        
        end
        
        def api_key
            login_required
            if request.post?
                current_user.generate_api_key
            else
                current_user.api_key
            end
        end
        
        def forgot_password
            # Always redirect if logged in
            if current_user
                flash[:message] = 'You are currently logged in. You may change your password now.'
                redirect_to :action => 'change_password'
                return
            end
            
            # Email disabled... we are unable to provide the password
            if !AccountConfiguration.config(:use_email_notification)
                flash[:message] = "We are currently unable to reset your password online.  Please contact the system admin at #{AccountConfiguration.config(:admin_email)} to reset your password."
                redirect_back_or_default :action => 'signin'
                return
            end

            if request.post?            
                # Handle the :post
                if params[:email].empty?
                    flash[:warning] = 'Please enter a valid email address.'
                elsif (user = User.find_by_email(params[:email])).nil?
                    flash[:warning] = "We could not find a user with the email address #{params[:email]}"
                else
                    begin
                        key = user.forgot_password
                        url = url_for(:action => 'reset_password', :password_reset_code => key)
                        UserNotify.deliver_forgot_password(user, url)
                        flash[:notice] = "Instructions on resetting your password have been emailed to #{params[:email]}"
                        redirect_back_or_default :action => 'signin'
                    rescue Exception => e
                        debugger
                        flash.now[:warning] = "There was a system error and we just don't know what happened.  Password could not be emailed to #{params[:email]}.  Please contact the system admin at #{AccountConfiguration.config(:admin_email)} and we'll see if a real human can help."
                    end
                end
            end
        end
        
        def reset_password
            password_reset_code = request.post? ? params[:password_reset_code] : params[:id]
            return unless !password_reset_code.nil?
            if @user = User.find_by_password_reset_code(password_reset_code)
                self.current_user = @user
                redirect_to(:action => 'change_password')
            else
                logger.error "Invalid Password Reset Code entered." 
                flash[:notice] = "Invalid Password Reset Code entered. Please check your Code and try again." 
            end
        end
        
        def change_password
            login_required
            return unless request.post?
            if (params[:password] == params[:password_confirmation])
                flash[:notice] = current_user.change_password(params[:password], params[:password_confirmation]) ? "Password changed" : "Password not changed" 
            else
                flash[:notice] = "Password mismatch" 
            end  
        end
        
        protected
        
        def protect?(action)
            if ['login', 'signup', 'forgot_password'].include?(action)
                return false
            else
                return true
            end
        end
        
        # Generate a template user for certain actions on get
        def generate_form_on_get
            case request.method
            when :get
                @user = User.new
                render
                return true
            end
            return false
        end
        
        # Generate a template user for certain actions on get
        def generate_filled_in
            get_user_to_act_on
            case request.method
            when :get
                render
                return true
            end
            return false
        end
        
        # returns the user object this method should act upon; only really
        # exists for other engines operating on top of this one to redefine...
        def get_user_to_act_on
            @user = User.find(session[:user_id])
        end
        
    end
    
end